package model;

import com.github.crab2died.annotation.ExcelField;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

//单位抽象类
abstract public class AbstractDepartment
{
	protected static DecimalFormat format = new DecimalFormat("#.#####");

	@ExcelField(title = "单位", order = 1)
	String departmentName;
	@ExcelField(title = "编制人数", order = 2)
	int authorizedNumber;
	@ExcelField(title = "实有人数", order = 3)
	int actualNumber = 0;
	@ExcelField(title = "完全匹配人数", order = 4)
	int totalMatchNumber;
	@ExcelField(title = "未完全匹配人数", order = 5)
	int notMatchNumber;

	@ExcelField(title = "岗位匹配人数", order = 6)
	int quarterMatchNumber;
	@ExcelField(title = "等级匹配人数", order = 7)
	int rankMatchNumber;
	@ExcelField(title = "专业匹配人数", order = 8)
	int professionMatchNumber;
	@ExcelField(title = "大专业匹配人数", order = 9)
	int mainProfessionMatchNumber;

	@ExcelField(title = "人数匹配率\n[1-(|实有-编制|)/编制]", order = 10)
	double numberMatchRate;
	@ExcelField(title = "人数超缺率\n[(实有-编制)/编制]", order = 11)
	double numberMoreOrLessRate;
	//	@ExcelField(title = "完全匹配率\n[完全匹配人数/编制人数]", order = 11)
	double totalMatchRate;

	//	@ExcelField(title = "专业及等级匹配率\n[专业及等级匹配人数/编制人数]", order = 13)
	double rankMatchRate;

	//	@ExcelField(title = "专业及岗位匹配率\n[专业及岗位匹配人数/编制人数]", order = 14)
	double quarterMatchRate;

	//	@ExcelField(title = "大专业及岗位匹配率\n[大专业及岗位匹配人数/编制人数]", order = 15)
	double mainProfessionMatchRate;

	@ExcelField(title = "综合匹配率", order = 12)
	double syntheticMatchRate;

	// 下级单位完全匹配率加权平均值
	protected double subAverageMatchRate;

	// 该单位所有未完全匹配编制岗位链表
	public final List<AbstractModel> notMatchAuthorizedModels = new ArrayList<>();

	// 该单位所有未完全匹配实有人员链表
	public List<AbstractModel> notMatchActualModels = new ArrayList<>();

	// 下级单位链表
	protected List<AbstractDepartment> subDepartments;
	protected boolean hasSubDepartment;

	abstract public boolean hasSubDepartment();

	abstract public boolean isSubDepartmentInThis(
			AbstractDepartment department);

	abstract public String departmentName();

	abstract public void calculateAdditionalData();

	public AbstractDepartment()
	{
		hasSubDepartment = hasSubDepartment();
		if (hasSubDepartment)
			subDepartments = new ArrayList<>();
	}

	public void addSubDepartment(AbstractDepartment subDepartment)
	{
		if (!hasSubDepartment)
			return;
		subDepartments.add(subDepartment);
		notMatchAuthorizedModels.addAll(subDepartment.notMatchAuthorizedModels);
		notMatchActualModels.addAll(subDepartment.notMatchActualModels);
	}

	public void calculateStatisticData()
	{
		departmentName = departmentName();
		authorizedNumber = authorizedNumber();
		actualNumber = actualNumber();
		totalMatchNumber = totalMatchNumber();
		notMatchNumber = actualNumber - totalMatchNumber;
		quarterMatchNumber = quarterMatchNumber();
		rankMatchNumber = rankMatchNumber();
		professionMatchNumber = professionMatchNumber();

		double authorizedN = authorizedNumber;
		numberMatchRate = 1 - Math.abs(actualNumber - authorizedNumber) / authorizedN;
		numberMoreOrLessRate = (actualNumber - authorizedNumber) / authorizedN;
		//		totalMatchRate = totalMatchNumber / authorizedN;

		syntheticMatchRate = (totalMatchNumber
				+ (quarterMatchNumber + rankMatchNumber + professionMatchNumber
				+ mainProfessionMatchNumber / 2.0) / 3.0)
				/ authorizedN;
		subAverageMatchRate = subAverageMatchRate();

		if (format != null)
		{
			numberMatchRate = Double.parseDouble(format.format(numberMatchRate));
			numberMoreOrLessRate = Double
					.parseDouble(format.format(numberMoreOrLessRate));
			//			totalMatchRate = Double.valueOf(format.format(totalMatchRate));
			//			rankMatchRate = Double.valueOf(format.format(rankMatchRate));
			//			quarterMatchRate = Double.valueOf(format.format(quarterMatchRate));
			//			mainProfessionMatchRate = Double
			//					.valueOf(format.format(mainProfessionMatchRate));
			subAverageMatchRate = Double
					.parseDouble(format.format(subAverageMatchRate));

			syntheticMatchRate = Double
					.parseDouble(format.format(syntheticMatchRate));
		}
		calculateAdditionalData();
	}

	private int actualNumber()
	{
		int n = 0;
		if (hasSubDepartment)
		{
			for (AbstractDepartment subDepartment : subDepartments)
				n += subDepartment.actualNumber;
		} else
		{
			for (AbstractModel model : notMatchActualModels)
				n += model.number;
		}
		return n;
	}

	private int authorizedNumber()
	{
		int n = 0;
		if (hasSubDepartment)
		{
			for (AbstractDepartment subDepartment : subDepartments)
				n += subDepartment.authorizedNumber;
		} else
		{
			for (AbstractModel model : notMatchAuthorizedModels)
				n += model.number;
		}
		return n;
	}

	private double subAverageMatchRate()
	{
		if (!hasSubDepartment)
			return 0;
		double totalRate = 0;
		for (AbstractDepartment subDepartment : subDepartments)
			totalRate += subDepartment.syntheticMatchRate
					* subDepartment.authorizedNumber;
		return totalRate / authorizedNumber;
	}

	private List<AbstractModel> initTempNotMatchAuthorizedModels()
	{
		List<AbstractModel> tempAuthorizedModels = new ArrayList<>();
		for (AbstractModel model : notMatchAuthorizedModels)
		{
			model.tempNumber = model.number;
			tempAuthorizedModels.add(model);
		}
		return tempAuthorizedModels;
	}

	private int totalMatchNumber()
	{
		int totalMatchNumber = 0;
		if (hasSubDepartment)
		{
			for (AbstractDepartment subDepartment : subDepartments)
				totalMatchNumber += subDepartment.totalMatchNumber;
		}
		// 未匹配人员链表
		Iterator<AbstractModel> actualIterator = notMatchActualModels.listIterator();
		while (actualIterator.hasNext())
		{
			AbstractModel actualModel = actualIterator.next();
			int number = actualModel.number;
			for (int i = 0; i < number; i++)
			{
				Iterator<AbstractModel> authorizedIterator = notMatchAuthorizedModels.listIterator();
				while (authorizedIterator.hasNext())
				{
					AbstractModel authorizedModel = authorizedIterator.next();
					if (actualModel.isTotalMatch(authorizedModel))
					{
						transportTotalMatchModel(actualModel);
						totalMatchNumber++;
						actualModel.number--;
						authorizedModel.number--;
						if (actualModel.number == 0)
							actualIterator.remove();
						if (authorizedModel.number == 0)
							authorizedIterator.remove();
						break;
					}
				}
			}
		}
		return totalMatchNumber;
	}

	protected void transportTotalMatchModel(AbstractModel model)
	{
	}

	private int quarterMatchNumber()
	{
		int matchNumber = 0;
		List<AbstractModel> tempAuthorizedNotMatchModels = initTempNotMatchAuthorizedModels();

		for (AbstractModel actualModel : notMatchActualModels)
		{
			for (int i = 0; i < actualModel.number; i++)
			{
				Iterator<AbstractModel> authorizedIterator = tempAuthorizedNotMatchModels.listIterator();
				while (authorizedIterator.hasNext())
				{
					AbstractModel authorizedModel = authorizedIterator.next();
					if (actualModel.isQuarterMatch(authorizedModel))
					{
						matchNumber++;
						authorizedModel.tempNumber--;
						if (authorizedModel.tempNumber == 0)
							authorizedIterator.remove();
						break;
					}
				}

//				for (AbstractModel authorizedModel : tempAuthorizedNotMatchModels)
//				{
//					if (actualModel.isQuarterMatch(authorizedModel))
//					{
//						matchNumber++;
//						authorizedModel.tempNumber--;
//						if (authorizedModel.tempNumber == 0)
//							tempAuthorizedNotMatchModels.remove(authorizedModel);
//						break;
//					}
//				}
			}
		}
		tempAuthorizedNotMatchModels = null;
		return matchNumber;
	}

	private int rankMatchNumber()
	{
		int matchNumber = 0;
		List<AbstractModel> tempAuthorizedNotMatchModels = initTempNotMatchAuthorizedModels();

		for (AbstractModel actualModel : notMatchActualModels)
		{
			for (int i = 0; i < actualModel.number; i++)
			{
				Iterator<AbstractModel> authorizedIterator = tempAuthorizedNotMatchModels.listIterator();
				while (authorizedIterator.hasNext())
				{
					AbstractModel authorizedModel = authorizedIterator.next();
					if (actualModel.isRankMatch(authorizedModel))
					{
						matchNumber++;
						authorizedModel.tempNumber--;
						if (authorizedModel.tempNumber == 0)
							authorizedIterator.remove();
						break;
					}
				}
//				for (AbstractModel authorizedModel : tempAuthorizedNotMatchModels)
//				{
//					if (actualModel.isRankMatch(authorizedModel))
//					{
//						matchNumber++;
//						authorizedModel.tempNumber--;
//						if (authorizedModel.tempNumber == 0)
//							tempAuthorizedNotMatchModels.remove(authorizedModel);
//						break;
//					}
//				}
			}
		}
		tempAuthorizedNotMatchModels = null;
		return matchNumber;
	}

	private int professionMatchNumber()
	{
		int matchNumber = 0;
		List<AbstractModel> tempAuthorizedNotMatchModels = initTempNotMatchAuthorizedModels();
		// 未匹配人员链表
		List<AbstractModel> sNotMatchModels = new ArrayList<>();
		for (AbstractModel actualModel : notMatchActualModels)
		{
			for (int i = 0; i < actualModel.number; i++)
			{
				int authorizedIndex = 0, notMatchCount = 0;
				for (AbstractModel authorizedModel : tempAuthorizedNotMatchModels)
				{
					if (actualModel.isProfessionMatch(authorizedModel))
					{
						matchNumber++;
						authorizedModel.tempNumber--;
						if (authorizedModel.tempNumber == 0)
							tempAuthorizedNotMatchModels.remove(authorizedModel);
						break;
					}
					authorizedIndex++;
					if (authorizedIndex == tempAuthorizedNotMatchModels.size())
					{
						notMatchCount++;
						actualModel.tempNumber = notMatchCount;
						if (notMatchCount == 1)
							sNotMatchModels.add(actualModel);
					}

				}
			}
		}
		mainProfessionMatchNumber = 0;
		for (AbstractModel actualModel : sNotMatchModels)
		{
			for (int i = 0; i < actualModel.tempNumber; i++)
				for (AbstractModel authorizedModel : tempAuthorizedNotMatchModels)
				{
					if (actualModel.isMainProfessionMatch(authorizedModel))
					{
						mainProfessionMatchNumber++;
						authorizedModel.tempNumber--;
						if (authorizedModel.tempNumber == 0)
							tempAuthorizedNotMatchModels.remove(authorizedModel);
						break;
					}
				}
		}
		tempAuthorizedNotMatchModels = null;
		sNotMatchModels = null;
		return matchNumber;
	}

	//	public void printModels()
	//	{
	//		System.out.println(departmentName + "单位：");
	//		for (Model model : authorizedModels)
	//			System.out.println(model);
	//		System.out.println();
	//		for (Model model : actualModels)
	//			System.out.println(model);
	//	}

	public void printInfo()
	{
		System.out.println(departmentName + "单位 [ 编制人数：" + authorizedNumber
				+ "， 实有人数：" + actualNumber + "， 完全匹配人数：" + totalMatchNumber
				+ "， 未匹配人数：" + notMatchNumber + "， 完全匹配率："
				+ syntheticMatchRate + " ]");
	}
	public String getDepartmentName()
	{
		return departmentName;
	}
	public void setDepartmentName(String departmentName)
	{
		this.departmentName = departmentName;
	}
	public int getAuthorizedNumber()
	{
		return authorizedNumber;
	}
	public void setAuthorizedNumber(int authorizedNumber)
	{
		this.authorizedNumber = authorizedNumber;
	}
	public int getActualNumber()
	{
		return actualNumber;
	}
	public void setActualNumber(int actualNumber)
	{
		this.actualNumber = actualNumber;
	}
	public int getTotalMatchNumber()
	{
		return totalMatchNumber;
	}
	public void setTotalMatchNumber(int totalMatchNumber)
	{
		this.totalMatchNumber = totalMatchNumber;
	}
	public int getNotMatchNumber()
	{
		return notMatchNumber;
	}
	public void setNotMatchNumber(int notMatchNumber)
	{
		this.notMatchNumber = notMatchNumber;
	}
	public int getRankMatchNumber()
	{
		return rankMatchNumber;
	}
	public void setRankMatchNumber(int professionRankMatchNumber)
	{
		this.rankMatchNumber = professionRankMatchNumber;
	}
	public int getQuarterMatchNumber()
	{
		return quarterMatchNumber;
	}
	public void setQuarterMatchNumber(int professionQuarterMatchNumber)
	{
		this.quarterMatchNumber = professionQuarterMatchNumber;
	}
	public int getMainProfessionMatchNumber()
	{
		return mainProfessionMatchNumber;
	}
	public void setMainProfessionMatchNumber(
			int quarterMainProfessionMatchNumber)
	{
		this.mainProfessionMatchNumber = quarterMainProfessionMatchNumber;
	}
	public double getNumberMatchRate()
	{
		return numberMatchRate;
	}
	public void setNumberMatchRate(double numberMatchRate)
	{
		this.numberMatchRate = numberMatchRate;
	}
	public double getNumberMoreOrLessRate()
	{
		return numberMoreOrLessRate;
	}
	public void setNumberMoreOrLessRate(double numberMoreOrLessRate)
	{
		this.numberMoreOrLessRate = numberMoreOrLessRate;
	}
	public double getTotalMatchRate()
	{
		return totalMatchRate;
	}
	public void setTotalMatchRate(double totalMatchRate)
	{
		this.totalMatchRate = totalMatchRate;
	}
	public double getRankMatchRate()
	{
		return rankMatchRate;
	}
	public void setRankMatchRate(double professionRankMatchRate)
	{
		this.rankMatchRate = professionRankMatchRate;
	}
	public double getQuarterMatchRate()
	{
		return quarterMatchRate;
	}
	public void setQuarterMatchRate(double professionQuarterMatchRate)
	{
		this.quarterMatchRate = professionQuarterMatchRate;
	}
	public double getSyntheticMatchRate()
	{
		return syntheticMatchRate;
	}
	public void setSyntheticMatchRate(double syntheticMatchRate)
	{
		this.syntheticMatchRate = syntheticMatchRate;
	}
	public double getSubAverageMatchRate()
	{
		return subAverageMatchRate;
	}
	public void setSubAverageMatchRate(double subAverageMatchRate)
	{
		this.subAverageMatchRate = subAverageMatchRate;
	}
	public double getMainProfessionMatchRate()
	{
		return mainProfessionMatchRate;
	}
	public void setMainProfessionMatchRate(
			double mainProfessionQuarterMatchRate)
	{
		this.mainProfessionMatchRate = mainProfessionQuarterMatchRate;
	}
	public int getProfessionMatchNumber()
	{
		return professionMatchNumber;
	}
	public void setProfessionMatchNumber(int professionMatchNumber)
	{
		this.professionMatchNumber = professionMatchNumber;
	}
}
